#!/usr/bin/python
# -*- Python -*-

# charozt -- An Asterisk VoIP Music-On-Hold Tool for GNOME.

# Copyright (c) 2009 8Layer Technologies, Inc.  All rights reserved.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

# Any 8Layer Technologies trademarks that are incorporated
# in the source code or documentation are not subject to the
# GNU General Public License and may only be used or replicated with
# the express permission of 8Layer Technologies, Inc.

# Authors:
#                Joel Bryan Juliano <jbjuliano@8layertech.com>
#                Meric B. Mara <mbmara@8layertech.com>

import gobject
gobject.threads_init()
import gtk
import pexpect
import sys
import time
import os
import os.path
import fcntl
import threading
import random

from operator import setitem

# define constants
COMBOBOX_MENU_CONVERT_IMG = 'audio-x-generic'
COMBOBOX_MENU_UPLOAD_IMG = 'network-server'
PID_FILE = "/tmp/charozt.pid"
COMBOBOX_MENU_CONVERT_MSG = "Convert Audio"
COMBOBOX_MENU_UPLOAD_MSG = "Upload to Server"
CONVERTER_SAVE_FOLDER_MSG = "Save Folder:"
CONVERTER_FILE_CHOOSER_MSG = "Save Location..."
UPLOADER_MSG_STRING_SERVER = "<b>Asterisk Server Details</b>"
UPLOADER_MSG_STRING_SERVER_NAME = "Server Name:"        
UPLOADER_MSG_STRING_SERVER_PATH = "Server Path:"
UPLOADER_MSG_STRING_AUTH = "<b>Authentication Details</b>"
UPLOADER_MSG_STRING_AUTH_NAME = "Username:"
UPLOADER_MSG_STRING_AUTH_PASSWORD = "Password:"
MISSING_DEPS_ERROR = "Program cannot continue and will now exit...\n\n\
Charozt requires 'ffmpeg' package to continue."
MISSING_INPUT_ERROR = "One of the required values is empty"
EMPTY_LISTSTORE_ERROR = "No files selected"
MOH_DEFAULT_PATH = "/var/lib/asterisk/moh"
CHAROZT_ABOUT_LOGO = "/usr/share/pixmaps/charozt-logo.png"
CONVERSION_SUCCESS = "File Conversion Successful!"
UPLOADING_SUCCESS = "File Upload Successful!"

# lock the pid process into single instance
fp = open(PID_FILE, 'w')
try:
    fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    sys.exit(0)

# initialize different server events
server_response = [
                       'assword:',
                       'connecting (yes/no)?',
                       'Host key verification failed.',
                       'Connection refused',
                       'route to host',
                       'from'
                  ]

# define liststore columns
(
  COLUMN_ID,
  COLUMN_FILES
) = range(2)

# initialize liststore default values
liststore_defaults_converter = []
liststore_defaults_uploader = []

# create notebook
notebook = gtk.Notebook()
notebook.set_show_tabs(False)
notebook.set_show_border(False)
notebook.set_resize_mode(gtk.RESIZE_PARENT)

def clean_liststore(liststore):
    result = []
    for el in liststore:
        if hasattr(el, "__iter__") and not isinstance(el, basestring):
            result.extend(clean_liststore(el))
        else:
            result.append(el)
    result = filter(lambda x: x != 0, result)
    d = {}
    map(setitem, (d,)*len(result), result, [])
    return d.keys()

class _IdleObject(gobject.GObject):
    """
    Override gobject.GObject to always emit signals in the main thread
    by emmitting on an idle handler
    """
    def __init__(self):
        gobject.GObject.__init__(self)

    def emit(self, *args):
        gobject.idle_add(gobject.GObject.emit,self,*args)
        
class NewThread(threading.Thread, _IdleObject):
    """
    Cancellable thread which uses gobject signals to return information
    to the GUI.
    """
    __gsignals__ =  { 
            "completed": (
                gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []),
            "progress": (
                gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [
                gobject.TYPE_FLOAT])        #percent complete
            }

    def __init__(self, *args):
        threading.Thread.__init__(self)
        _IdleObject.__init__(self)
        self.cancelled = False
        self.data = args[0]

    def cancel(self):
        """
        Threads in python are not cancellable, so we implement our own
        cancellation logic
        """
        self.cancelled = True

    def run(self):
        print "Running %s" % str(self)
        for i in range(self.data):
            if self.cancelled:
                break
            time.sleep(0.1)
            self.emit("progress", i/float(self.data)*100)            
        self.emit("completed")

class Charozt(gtk.Window):
   
    def __init__(self, parent=None):

        # initialize window
        gtk.Window.__init__(self)
        try:
            self.set_screen(parent.get_screen())
        except AttributeError:
            self.connect('destroy', lambda *w: gtk.main_quit())

        # dependency checks
        check_dependencies(self)

        # set window options
        self.set_title(self.__class__.__name__)
        self.set_border_width(10)
        self.set_default_size(380, 500)
        self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
        self.set_icon_from_file("/usr/share/icons/hicolor/24x24/apps/charozt-icon.png")
        self.set_modal(False)

        # add global container
        vbox = gtk.VBox(False, 5)
        self.add(vbox)

        # add global horizontal container
        hbox = gtk.HBox(False, 0)
        vbox.pack_start(hbox, False, False)

        # create the combobox for upload/convert options
        icon_theme = gtk.icon_theme_get_default ()        
        combobox_menu = gtk.ListStore(gtk.gdk.Pixbuf, str)
        image = gtk.Image()
        stock = icon_theme.load_icon (COMBOBOX_MENU_CONVERT_IMG, 16, 0)
        combobox_menu.append((stock, \
        COMBOBOX_MENU_CONVERT_MSG))
        stock = icon_theme.load_icon (COMBOBOX_MENU_UPLOAD_IMG, 16, 0)
        combobox_menu.append((stock, \
        COMBOBOX_MENU_UPLOAD_MSG))
        combobox = gtk.ComboBox(combobox_menu)
        combobox.set_model(combobox_menu)
        pixbuf = gtk.CellRendererPixbuf()
        text = gtk.CellRendererText()
        combobox.pack_start(pixbuf, False)
        combobox.add_attribute(pixbuf, "pixbuf", 0)
        combobox.pack_start(text, False)
        combobox.add_attribute(text, "text", 1)
        combobox.connect('changed', self.changed_cb)
        combobox.set_active(0)
        hbox.add(combobox)

        # add notebook to vbox
        vbox.pack_start(notebook, True, True)

        # create scrollwindow widget
        for scrollwindows in ('converter_sw', 'uploader_sw'):
            globals()[scrollwindows] = gtk.ScrolledWindow()
            globals()[scrollwindows].set_shadow_type(gtk.SHADOW_ETCHED_IN)
            globals()[scrollwindows].set_policy(gtk.POLICY_AUTOMATIC, \
                                                gtk.POLICY_AUTOMATIC)

        # create treeview model
        for treeview_models in ('converter_model', 'uploader_model'):
            if treeview_models == 'converter_model':
                globals()[treeview_models] = self.__create_model\
                                         ('converter')
            else:
                globals()[treeview_models] = self.__create_model\
                                         ('uploader')

        # create treeview widget
        for treeview_widgets in ('converter_treeview', 'uploader_treeview'):
            if treeview_widgets == 'converter_treeview':
                globals()[treeview_widgets] = gtk.TreeView(converter_model)
            else:
                globals()[treeview_widgets] = gtk.TreeView(uploader_model)
            globals()[treeview_widgets].set_rules_hint(True)
            globals()[treeview_widgets].get_selection().set_mode\
                                                       (gtk.SELECTION_SINGLE)
            self.__add_columns(globals()[treeview_widgets])

        converter_sw.add(converter_treeview)
        uploader_sw.add(uploader_treeview)

        # create box containers for convert & upload page
        for horizontal_box in ('converter_hbox', 'uploader_hbox'):
            globals()[horizontal_box] = gtk.HBox(False, 0)

        for container_box in ('converter_box', 'uploader_box'):
            globals()[container_box] = gtk.VBox(False, 0)
            if container_box == 'converter_box':
                globals()[container_box].pack_start(converter_hbox,\
                                                    False, False)
            else:
                globals()[container_box].pack_start(uploader_hbox, False, False)

        for toolbar in ('converter_toolbar', 'uploader_toolbar'):
            globals()[toolbar] = gtk.Toolbar()
            globals()[toolbar].set_style(gtk.TOOLBAR_BOTH)
            if toolbar == 'converter_toolbar':
                converter_hbox.pack_start(globals()[toolbar], True, True)
            else:
                uploader_hbox.pack_start(globals()[toolbar], True, True)

        # create add buttons
        for add_toolbuttons in ('converter_toolbutton', 'uploader_toolbutton'):
            globals()[add_toolbuttons] = gtk.ToolButton("Add")
            globals()[add_toolbuttons].set_stock_id(gtk.STOCK_ADD)
            if add_toolbuttons == 'converter_toolbutton':
                globals()[add_toolbuttons].connect("clicked",\
                                           self.on_add_item_clicked,\
                                           converter_model)
                converter_toolbar.insert(globals()[add_toolbuttons], -1)
            else:
                globals()[add_toolbuttons].connect("clicked",\
                                           self.on_add_item_clicked,\
                                           uploader_model)
                uploader_toolbar.insert(globals()[add_toolbuttons], -1)

        # create remove buttons
        for remove_toolbuttons in ('converter_toolbutton',\
                                   'uploader_toolbutton'):
            globals()[remove_toolbuttons] = gtk.ToolButton("Remove")
            globals()[remove_toolbuttons].set_stock_id(gtk.STOCK_REMOVE)
            if remove_toolbuttons == 'converter_toolbutton':
                globals()[remove_toolbuttons].connect("clicked",\
                                           self.on_remove_item_clicked,\
                                           converter_treeview)
                converter_toolbar.insert(globals()[remove_toolbuttons], -1)
            else:
                globals()[remove_toolbuttons].connect("clicked",\
                                           self.on_remove_item_clicked,\
                                           uploader_treeview)
                uploader_toolbar.insert(globals()[remove_toolbuttons], -1)

        # add separators
        for toolbar in ('converter_toolbar', 'uploader_toolbar'):
            if toolbar == 'converter_toolbar':
                converter_separator = gtk.SeparatorToolItem()
                globals()[toolbar].insert(converter_separator, -1)
            else:
                uploader_separator = gtk.SeparatorToolItem()
                globals()[toolbar].insert(uploader_separator, -1)

        # create convert / upload buttons
        for toolbar in ('converter_toolbar', 'uploader_toolbar'):
            if toolbar == 'converter_toolbar':
                converter_toolbutton = gtk.ToolButton("Add")
                converter_toolbutton.set_stock_id(gtk.STOCK_CONVERT)
                converter_toolbutton.connect("clicked", \
                                              self.on_convert_button_clicked,\
                                              liststore_defaults_converter)
                globals()[toolbar].insert(converter_toolbutton, -1)
            else:
                uploader_toolbutton = gtk.ToolButton("Add")
                uploader_toolbutton.set_stock_id(gtk.STOCK_CONNECT)
                uploader_toolbutton.connect("clicked", \
                                              self.on_upload_button_clicked,\
                                              liststore_defaults_uploader)
                globals()[toolbar].insert(uploader_toolbutton, -1)

        # add convert page particulars
        label_hbox = gtk.HBox(False, 0)
        label = gtk.Label()
        label.set_label(CONVERTER_SAVE_FOLDER_MSG)
        label_hbox.pack_start(label, True, True)

        hbox = gtk.HBox(False, 0)
        hbox.pack_start(label_hbox, False, False)
        self.converter_chooser = gtk.FileChooserButton \
                                (CONVERTER_FILE_CHOOSER_MSG)
        self.converter_chooser.set_action \
                                (gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
        self.converter_chooser.set_current_folder \
                                (os.path.expanduser("~"))
        hbox.pack_start(self.converter_chooser, True, True)
        converter_box.pack_start(hbox, False, False)

        uploader_hseparator = gtk.HSeparator()
        converter_hseparator = gtk.HSeparator()
                
        uploader_box.pack_start(uploader_hseparator, False, False)
        converter_box.pack_start(converter_hseparator, False, False)

        # add the scrollwindow widget for both pages
        converter_box.pack_start(converter_sw)
        uploader_box.pack_start(uploader_sw)

        # create common about & quit buttons
        hbox = gtk.HBox(True, 0)       
        vbox.pack_start(hbox, False, False)                 
        hbuttonbox = gtk.HButtonBox()
        hbuttonbox.set_border_width(5)
        hbuttonbox.set_layout(gtk.BUTTONBOX_START)
        hbox.pack_start(hbuttonbox, False, False)

        button = gtk.Button(stock=gtk.STOCK_ABOUT)
        button.connect("clicked", self.on_about_button_clicked)
        hbuttonbox.pack_start(button)

        hbuttonbox = gtk.HButtonBox()
        hbuttonbox.set_border_width(5)
        hbuttonbox.set_layout(gtk.BUTTONBOX_EDGE)
        hbox.pack_start(hbuttonbox, False, False)

        button = gtk.Button(stock=gtk.STOCK_QUIT)
        button.connect("clicked", lambda *w: gtk.main_quit())
        hbuttonbox.pack_start(button)

        """ TODO: add progress bar on threaded upload and convert processes
        # create the progressbar
        hseparator = gtk.HSeparator()
        vbox.pack_start(hseparator, False, True)
        hbox = gtk.HBox(True, 10)
        align = gtk.Alignment(1.0, 0.0, 0, 0)
        hbox.pack_start(align, False, False, 5)
        self.pbar = gtk.ProgressBar()
        hbox.add(self.pbar)
        vbox.pack_start(hbox, False, True)
        """
        
        # add upload page particulars
        hbox = gtk.HBox(False, 0)
        hbox.set_border_width(5)
        
        label = gtk.Label()
        label.set_markup(UPLOADER_MSG_STRING_SERVER)
        hbox.pack_start(label, False, False)
        uploader_box.pack_start(hbox, False, False)

        hbox = gtk.HBox(False, 0)
        hbox.set_border_width(5)
        label = gtk.Label()
        label.set_markup(UPLOADER_MSG_STRING_SERVER_NAME)
        hbox.pack_start(label, False, False)

        hbox = gtk.HBox(True, 0)
        hbox.set_border_width(5)                
        self.serverip_entry = gtk.Entry()
        hbox.pack_start(label, False, False)
        hbox.pack_start(self.serverip_entry, False, False)
        uploader_box.pack_start(hbox, False, False)

        hbox = gtk.HBox(False, 0)
        hbox.set_border_width(5)
        label = gtk.Label()
        label.set_markup(UPLOADER_MSG_STRING_SERVER_PATH)
        hbox.pack_start(label, False, False)

        hbox = gtk.HBox(True, 0)
        hbox.set_border_width(5)                
        self.path_entry = gtk.Entry()
        self.path_entry.set_text(MOH_DEFAULT_PATH)
        self.path_entry.set_sensitive(False)       
        hbox.pack_start(label, False, False)
        hbox.pack_start(self.path_entry, False, False)
        uploader_box.pack_start(hbox, False, False)

        hbox = gtk.HBox(False, 0)
        hbox.set_border_width(5)
        label = gtk.Label()
        label.set_markup(UPLOADER_MSG_STRING_AUTH)
        hbox.pack_start(label, False, False)
        uploader_box.pack_start(hbox, False, False)

        hbox = gtk.HBox(False, 0)
        hbox.set_border_width(5)
        label = gtk.Label()
        label.set_markup(UPLOADER_MSG_STRING_AUTH_NAME)
        hbox.pack_start(label, False, False)

        hbox = gtk.HBox(True, 0)
        hbox.set_border_width(5)                
        self.userid_entry = gtk.Entry()
        hbox.pack_start(label, False, False)
        hbox.pack_start(self.userid_entry, False, False)
        uploader_box.pack_start(hbox, False, False)
        
        hbox = gtk.HBox(False, 0)
        hbox.set_border_width(5)
        label = gtk.Label()
        label.set_markup(UPLOADER_MSG_STRING_AUTH_PASSWORD)
        hbox.pack_start(label, False, False)

        hbox = gtk.HBox(True, 0)
        hbox.set_border_width(5)                
        self.passwd_entry = gtk.Entry()
        self.passwd_entry.set_visibility(False)        
        hbox.pack_start(label, False, False)
        hbox.pack_start(self.passwd_entry, False, False)
        uploader_box.pack_start(hbox, False, False)        

        notebook.insert_page(converter_box, gtk.Label("Converter"))
        notebook.insert_page(uploader_box, gtk.Label("Uploader"))

        self.show_all()

    def changed_cb(self, combobox):
    
        cb_model = combobox.get_model()
        index = combobox.get_active()
        if index:
            notebook.set_current_page(1)
        else:
            notebook.set_current_page(0)
        return

    def __create_model(self, model_type):

        # create list store
        model = gtk.ListStore(
            gobject.TYPE_INT,
            gobject.TYPE_STRING
       )

        # add items
        if model_type == 'converter':
            for item in liststore_defaults_converter:
                iter = model.append()

                model.set (iter,
                      COLUMN_ID, item[COLUMN_ID],
                      COLUMN_FILES, item[COLUMN_FILES]
                )
        else:
            for item in liststore_defaults_uploader:
                iter = model.append()

                model.set (iter,
                      COLUMN_ID, item[COLUMN_ID],
                      COLUMN_FILES, item[COLUMN_FILES]
                )
        return model

    def __add_columns(self, treeview):

        if treeview == converter_treeview:
            model = converter_treeview.get_model()
        else:
            model = uploader_treeview.get_model()

        renderer = gtk.CellRendererText()
        renderer.set_data("column", COLUMN_ID)

        column = gtk.TreeViewColumn("Number", renderer, text=COLUMN_ID)
        column.set_visible(False)

        if treeview == converter_treeview:
            converter_treeview.append_column(column)
        else:
            uploader_treeview.append_column(column)

        renderer = gtk.CellRendererText()
        renderer.set_data("column", COLUMN_FILES)

        if treeview == converter_treeview:
            column = gtk.TreeViewColumn("Conversion Queue", \
                                         renderer, text=COLUMN_FILES)
        else:
            column = gtk.TreeViewColumn("Upload Queue", renderer, \
                                         text=COLUMN_FILES)

        if treeview == converter_treeview:
            converter_treeview.append_column(column)
            converter_treeview.set_headers_visible(False)            
        else:
            uploader_treeview.append_column(column)
            uploader_treeview.set_headers_visible(False)                        

    def select_files(self, model_type):

        dialog = gtk.FileChooserDialog("Open..",
                                       None,
                                       gtk.FILE_CHOOSER_ACTION_OPEN,
                                       (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                        gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        dialog.set_default_response(gtk.RESPONSE_OK)

        if model_type == 'converter':
            filter = gtk.FileFilter()
            filter.set_name("MPEG Layer-3 Audio (*.mp3)")
            filter.add_mime_type("mpeg/mp3")
            filter.add_pattern("*.mp3")
            dialog.add_filter(filter)
        else:
            filter = gtk.FileFilter()
            filter.set_name("WAV-GSM/WAV49 Audio (*.wav)")
            filter.add_mime_type("audio/x-wav")
            filter.add_pattern("*.wav")
            dialog.add_filter(filter)

        response = dialog.run()
        if response == gtk.RESPONSE_OK:
            dialog.hide()
            return dialog.get_filename()
        elif response == gtk.RESPONSE_CANCEL:
            dialog.hide()
            return None

    def on_add_item_clicked(self, button, model):

        if model == converter_model:
        
            new_item = [0, self.select_files('converter')]
            if not new_item[1:] == [None]:
                if not new_item in liststore_defaults_converter:
                    liststore_defaults_converter.append(new_item)
                    iter = converter_model.append()
                    converter_model.set (iter,
                         COLUMN_FILES, new_item[COLUMN_FILES]
                    )
           
        else:
        
            new_item = [0, self.select_files('uploader')]
            if not new_item[1:] == [None]:
                if not new_item in liststore_defaults_uploader:
                    liststore_defaults_uploader.append(new_item)
                    iter = uploader_model.append()
                    uploader_model.set (iter,
                         COLUMN_FILES, new_item[COLUMN_FILES]
                    )

    def on_remove_item_clicked(self, button, treeview):

        if treeview == converter_treeview:
        
            selection = converter_treeview.get_selection()
            converter_model, iter = selection.get_selected()
            
            if iter:
            
                path = converter_model.get_path(iter)[0]
                converter_model.remove(iter)

                del liststore_defaults_converter[ path ]
                
        else:
        
            selection = uploader_treeview.get_selection()
            uploader_model, iter = selection.get_selected()
            
            if iter:
            
                path = uploader_model.get_path(iter)[0]
                uploader_model.remove(iter)

                del liststore_defaults_uploader[ path ]

    def on_convert_button_clicked(self, button, liststore):
    
        self.set_sensitive(False)
        
        convert_queue = clean_liststore(liststore)
        if not convert_queue == []:
            self.convert_files(convert_queue)            
        else:
            no_files_selected_dialog(self)
            
    def convert_files(self, files_list):
        save_location = self.converter_chooser.get_filename()        
        
        for filename in files_list:
            (shortname, extension) = os.path.splitext(filename)
            os.system("ffmpeg -i \"%s\" -y -ar 8000 -ac 1 -ab 64\
                     \"%s.wav\" -ar 8000 -ac 1 -ab 64 -f mulaw\
                     \"%s.pcm\" -map 0:0 -map 0:0" % (filename, shortname, shortname))
            os.system("mv \"%s.wav\" \"%s\"" % (shortname, save_location))
            os.system("rm -rf \"%s.pcm\"" % (shortname))
            
        convert_success_dialog(self)

    def on_upload_button_clicked(self, button, liststore):        
        
        self.set_sensitive(False)
        
        # flatten liststore and clear for any duplicates
        upload_queue = clean_liststore(liststore)

        # get text entry values
        serverip = self.serverip_entry.get_text()
        userid = self.userid_entry.get_text()
        passwd = self.passwd_entry.get_text()
        path = self.path_entry.get_text()

        # contain all configurations into a portable list
        server_config = [serverip, userid, passwd, path]

        # check if every text entry is filled up
        for x in serverip, userid, passwd, path:
            value = len(x)
            if value == 0:
                missing_input_dialog(self)
                return 0

        if not upload_queue == []:
            copy_files(self, upload_queue, server_config)
        else:
            no_files_selected_dialog(self)
    """ TODO: add when threading is implemented.
    def progress_timeout(self):
        if self.pbar_mode:
            self.pbar.pulse()
        else:
            new_val = self.pbar.get_fraction() + 0.01
            if new_val > 1.0:
                new_val = 0.0
            self.pbar.set_fraction(new_val)
        return True

    def start_progress_bar(self):
        self.timer = gobject.timeout_add (100, self.progress_timeout)
        self.toggle_activity_mode()

    def toggle_activity_mode(self):
        if self.pbar_mode:
            self.pbar.pulse()
        else:
            self.pbar.set_fraction(0.0)
            
    def stop_progress_bar(self):
        self.pbar_mode = 0
        self.toggle_activity_mode()
        gobject.source_remove(self.timer)
    """    
    def on_about_button_clicked(self, button):
    
        dialog = gtk.AboutDialog()
        logo = gtk.gdk.pixbuf_new_from_file(CHAROZT_ABOUT_LOGO)
        dialog.set_logo(logo)        
        dialog.set_name("Charozt")
        dialog.set_comments("Asterisk VoIP Music-On-Hold Tool for GNOME.")
        dialog.set_copyright("Copyright (c) 2009 8Layer Technologies, Inc.")
        dialog.set_license\
("Copyright (c) 2009 8Layer Technologies, Inc.  All rights reserved.\n\
\n\
This program is free software; you can redistribute it and/or modify\n\
it under the terms of the GNU General Public License as published by\n\
the Free Software Foundation; either version 2, or (at your option)\n\
any later version.\n\
\n\
This program is distributed in the hope that it will be useful,\n\
but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
See the GNU General Public License for more details.\n\
\n\
You should have received a copy of the GNU General Public License\n\
along with this program; if not, write to the Free Software\n\
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\n\
02110-1301, USA.\n\
\n\
Any 8Layer Technologies trademarks that are incorporated\n\
in the source code or documentation are not subject to the\n\
GNU General Public License and may only be used or replicated\n\
with the express permission of 8Layer Technologies, Inc.")
        dialog.set_wrap_license(False)
        dialog.set_website("http://www.8layertech.com")
        dialog.set_website_label("8Layer Technologies, Inc.")
        authors = ["Joel Bryan Juliano <jbjuliano@8layertech.com>",\
                   "Meric B. Mara <mmara@8layertech.com>"]
        artists = ["Spencer Sy <ssy@8layertech.com>"]
        documenters = ["Jaja del Rosario <jdrosario@8layertech.com>"]
        dialog.set_authors(authors)
        dialog.set_artists(artists)
        dialog.set_documenters(documenters)
        dialog.connect ("response", lambda d, r: d.destroy())
        dialog.show()

def no_files_selected_dialog(self):

    msg = gtk.MessageDialog(None,
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_ERROR,
                            gtk.BUTTONS_CLOSE,
                            EMPTY_LISTSTORE_ERROR)
    resp = msg.run()
    msg.destroy()
    if resp:
        self.set_sensitive(True)
    
def missing_input_dialog(self):

    msg = gtk.MessageDialog(None,
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_ERROR,
                            gtk.BUTTONS_CLOSE,
                            MISSING_INPUT_ERROR)
    resp = msg.run()
    msg.destroy()
    if resp:
        self.set_sensitive(True)
    
def missing_dependencies_dialog(self):

    msg = gtk.MessageDialog(None,
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_ERROR,
                            gtk.BUTTONS_CLOSE,
                            MISSING_DEPS_ERROR)
    resp = msg.run()
    msg.destroy()
    if resp:
       sys.exit()

def convert_success_dialog(self):

    msg = gtk.MessageDialog(None,
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_INFO,
                            gtk.BUTTONS_OK,
                            CONVERSION_SUCCESS)
    resp = msg.run()
    msg.destroy()
    if resp:
        self.set_sensitive(True)

def upload_success_dialog(self):

    msg = gtk.MessageDialog(None,
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_INFO,
                            gtk.BUTTONS_OK,
                            UPLOADING_SUCCESS)
    resp = msg.run()
    msg.destroy()
    if resp:
        self.set_sensitive(True)

def fix_known_hosts_dialog(self):

    dlg = gtk.MessageDialog(None, 
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_WARNING,
                            gtk.BUTTONS_NONE,
                           ('Host key verification failed.'))
    RESPONSE_DISCARD = 1
    RESPONSE_SAVE = 2
    dlg.add_buttons(('Create New'), RESPONSE_SAVE,
                    gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
    dlg.format_secondary_text(("Host key doesn't match with the server\n"
                               "Create a new host file?"))
    resp = dlg.run()
    dlg.destroy()
    if resp == RESPONSE_SAVE:
        return True
    else:
        return False
    self.set_sensitive(True)

def known_hosts_created_msg_dialog(self):
    msg = gtk.MessageDialog(None,
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_INFO,
                            gtk.BUTTONS_CLOSE,
                            "Host key successfully created\n"
                            "\nAll changes will take effect on next connection")
    resp = msg.run()
    msg.destroy()
    if resp:
        self.set_sensitive(True)
        

def disconnected_msg_dialog(self):
    msg = gtk.MessageDialog(None,
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_ERROR,
                            gtk.BUTTONS_CLOSE,
                            "Disconnected to server")
    resp = msg.run()
    msg.destroy()
    if resp:
        self.set_sensitive(True)
        

def connection_refused_dialog(self, server):
    msg = gtk.MessageDialog(None,
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_ERROR,
                            gtk.BUTTONS_CLOSE,
                            "Connection to %s refused" % (server))
    resp = msg.run()
    msg.destroy()
    if resp:
        self.set_sensitive(True)
        

def no_response_to_server_dialog(self, server):
    msg = gtk.MessageDialog(None,
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_ERROR,
                            gtk.BUTTONS_CLOSE,
                            "No response from %s" % (server))
    resp = msg.run()
    msg.destroy()
    if resp:
        self.set_sensitive(True)
        

def connection_timeout_dialog(self, server):
    msg = gtk.MessageDialog(None,
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_ERROR,
                            gtk.BUTTONS_CLOSE,
                            "Connection to %s timeout" % (server))
    resp = msg.run()
    msg.destroy()
    if resp:
        self.set_sensitive(True)
        

def no_route_to_host_dialog(self, server):
    msg = gtk.MessageDialog(None,
                            gtk.DIALOG_DESTROY_WITH_PARENT,
                            gtk.MESSAGE_ERROR,
                            gtk.BUTTONS_CLOSE,
                            "%s: No route to host" % (server))
    resp = msg.run()
    msg.destroy()
    if resp:
        self.set_sensitive(True)
        

def check_dependencies(self):
    check_if_exist = os.path.isfile('/usr/bin/ffmpeg')
    if not check_if_exist:
       missing_dependencies_dialog(self)

def copy_files_to_server(self, files_list, uid, ip_addr, dest_path, passwd):
    flag = False
    
    for x, y in enumerate(files_list):
        max_files = x

    for x, y in enumerate(files_list):
        (file_id, file_name) = x, y
        scp_command = pexpect.spawn('scp -r \"%s\" %s@%s:%s' % (file_name,
                                                       uid,
                                                       ip_addr,
                                                       dest_path))
        try:
            response = scp_command.expect (server_response)
            if response == 0:
               scp_command.sendline('%s' % passwd)
               scp_command.expect("\n")
            elif response == 1:
               scp_command.sendline('yes')
               scp_command.expect('assword:')
               scp_command.sendline('%s' % passwd)
            elif response == 2:
               if fix_known_hosts_dialog(self):
                  timestamp = time.strftime("%m%d%y_%I%M%S%p", time.localtime())           
                  known_hosts_file = os.environ.get('HOME')+"/.ssh/known_hosts"
                  known_hosts_backup = known_hosts_file + ".%s.bak" % (timestamp)
                  known_hosts = open(known_hosts_file, 'r')
                  known_hosts_old = known_hosts.read()
                  known_hosts.close()
                  os.rename(known_hosts_file, known_hosts_backup)
                  if not flag:
                     known_hosts_created_msg_dialog(self)
               else:
                  if not flag:
                     disconnected_msg_dialog(self)
            elif response == 3:
               if not flag:
                  connection_refused_dialog(self, ip_addr)
            elif response == 4:
               if not flag:
                  no_route_to_host_dialog(self, ip_addr)
            scp_command.expect(pexpect.EOF)
            scp_command.close()
            if file_id == max_files:
               upload_success_dialog(self)
            flag = True
        except pexpect.TIMEOUT:
           if not flag:
              connection_timeout_dialog(self, ip_addr)
        except pexpect.EOF:
           if not flag:
              no_response_to_server_dialog(self, ip_addr)

def copy_files(self, files, config):
                           
    # extract config list values to variables
    values = iter(config)
    for x in ('ip_addr', 'uid', 'passwd', 'dest_path'):
        globals()[x] = values.next()

    # process file list values for copying
    copy_files_to_server(self, files, uid, ip_addr, dest_path, passwd)

def main():
    Charozt()
    gtk.main()    

if __name__ == '__main__':

    gtk.gdk.threads_init()
    main()
